# Key.java

    package org.codefilarete.stalactite.sql.ddl.structure;

    import org.codefilarete.stalactite.query.api.Fromable;
    import org.codefilarete.stalactite.query.api.JoinLink;
    import org.codefilarete.tool.collection.KeepOrderSet;

    /**
     * Representation of a database key such as Primary Key and Foreign Key, or columns of a join.
     * Can be composed of a single column or multiple ones as in composite key.
     *
     * @param <T> table owning the key, can also be a sub-query
     * @param <ID> object type composed by key columns, left unused here because no method refers to id
     * @author Guillaume Mary
     */
    public interface Key<T extends Fromable, ID /* unused in this class, left for clarity in all code using Key */> {

    	static <T extends Fromable, ID> KeyBuilder<T, ID> from(T table) {
    		return new KeyBuilder<>(table);
    	}

    	static <T extends Fromable, ID> Key<T, ID> ofSingleColumn(JoinLink<T, ID> column) {
    		return new KeySupport<T, ID>(column.getOwner(), new KeepOrderSet<>(column)) {
    			@Override
    			public boolean isComposed() {
    				return false;
    			}
    		};
    	}

    	T getTable();

    	KeepOrderSet<? extends JoinLink<T, ?>> getColumns();

    	boolean isComposed();

    	class KeyBuilder<T extends Fromable, ID> {

    		private final KeySupport<T, ID> keySupport;

    		private KeyBuilder(T table) {
    			keySupport = new KeySupport<>(table);
    		}

    		public KeyBuilder<T, ID> addColumn(JoinLink<T, ?> column) {
    			this.keySupport.addColumn(column);
    			return this;
    		}

    		public Key<T, ID> build() {
    			return keySupport;
    		}
    	}

    	class KeySupport<T extends Fromable, ID> implements Key<T, ID> {

    		private final T table;
    		private final KeepOrderSet<JoinLink<T, ?>> columns;

    		private KeySupport(T table) {
    			this(table, new KeepOrderSet<>());
    		}

    		private KeySupport(T table, KeepOrderSet<? extends JoinLink<T, ?>> columns) {
    			this.table = table;
    			this.columns = (KeepOrderSet<JoinLink<T, ?>>) columns;
    		}

    		@Override
    		public T getTable() {
    			return table;
    		}

    		@Override
    		public KeepOrderSet<JoinLink<T, ?>> getColumns() {
    			return columns;
    		}

    		private void addColumn(JoinLink<T, ?> column) {
    			this.columns.add((JoinLink<T, Object>) column);
    		}

    		@Override
    		public boolean isComposed() {
    			return columns.size() == 1;
    		}
    	}
    }